/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*                                                                    *
*        ***************************************************         *
*        *©2021-2031 LINUO Corporation All rights reserved *         *
*        ***************************************************         *
*                                                                    *
* FileName    : venc.c                                               *
*                                                                    *
* Author      : linus                                                *
*                                                                    *
* Email       : luoyaojun@sina.com                                   *
*                                                                    *
* Date        : 2024-3-27                                            *
*                                                                    *
* Description :                                                      *
*                                                                    *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "h_register.h"
#include "h_venc.h"
#include "rk_debug.h"
#include "rk_mpi_cal.h"
#include "rk_mpi_mb.h"
#include "rk_mpi_sys.h"
#include "rk_mpi_venc.h"

#include "venc.h"

static RK_CODEC_ID_E rockchip_venc_codec(HT_CODEC_ID codec)
{
    RK_CODEC_ID_E ret = RK_VIDEO_ID_AutoDetect;

    switch (codec)
    {
    case HT_VIDEO_ID_H264:
        ret = RK_VIDEO_ID_AVC;
        break;
    case HT_VIDEO_ID_H265:
        ret = RK_VIDEO_ID_HEVC;
        break;
    case HT_VIDEO_ID_JPEG:
        ret = RK_VIDEO_ID_JPEG;
        break;
    case HT_VIDEO_ID_VP9:
        ret = RK_VIDEO_ID_VP9;
        break;
    default:
        ret = RK_VIDEO_ID_AutoDetect;
        break;
    }

    return ret;
}

static RK_S32 rockchip_set_bitrate(VENC_RC_ATTR_S *pRcAttr, RK_U32 u32BitRate, RK_U32 u32BitRateMax,
                                   RK_U32 u32BitRateMin)
{
    switch (pRcAttr->enRcMode)
    {
    case VENC_RC_MODE_MJPEGCBR:
        pRcAttr->stMjpegCbr.u32BitRate = u32BitRate;
        break;
    case VENC_RC_MODE_H264CBR:
        pRcAttr->stH264Cbr.u32BitRate = u32BitRate;
        break;
    case VENC_RC_MODE_H265CBR:
        pRcAttr->stH265Cbr.u32BitRate = u32BitRate;
        break;
    case VENC_RC_MODE_MJPEGVBR:
        pRcAttr->stMjpegVbr.u32BitRate = u32BitRate;
#ifdef RK3588
        pRcAttr->stMjpegVbr.u32MaxBitRate = u32BitRateMax;
        pRcAttr->stMjpegVbr.u32MinBitRate = u32BitRateMin;
#endif
        break;
    case VENC_RC_MODE_H264VBR:
        pRcAttr->stH264Vbr.u32BitRate = u32BitRate;
#ifdef RK3588

        pRcAttr->stH264Vbr.u32MaxBitRate = u32BitRateMax;
        pRcAttr->stH264Vbr.u32MinBitRate = u32BitRateMin;
#endif
        break;
    case VENC_RC_MODE_H265VBR:
        pRcAttr->stH265Vbr.u32BitRate = u32BitRate;
#ifdef RK3588

        pRcAttr->stH265Vbr.u32MaxBitRate = u32BitRateMax;
        pRcAttr->stH265Vbr.u32MinBitRate = u32BitRateMin;
#endif
        break;
    case VENC_RC_MODE_H264AVBR:
        pRcAttr->stH264Avbr.u32BitRate = u32BitRate;
#ifdef RK3588

        pRcAttr->stH264Avbr.u32MaxBitRate = u32BitRateMax;
        pRcAttr->stH264Avbr.u32MinBitRate = u32BitRateMin;
#endif
        break;
    case VENC_RC_MODE_H265AVBR:
        pRcAttr->stH265Avbr.u32BitRate = u32BitRate;
#ifdef RK3588

        pRcAttr->stH265Avbr.u32MaxBitRate = u32BitRateMax;
        pRcAttr->stH265Avbr.u32MinBitRate = u32BitRateMin;
#endif
        break;
    default:
        return RK_ERR_VENC_NOT_SUPPORT;
    }

    return RK_SUCCESS;
}

static RK_S32 rockchip_set_fixqp(VENC_RC_ATTR_S *pRcAttr, RK_U32 u32FixIQp, RK_U32 u32FixPQp, RK_U32 u32FixBQp)
{
    switch (pRcAttr->enRcMode)
    {
    case VENC_RC_MODE_MJPEGFIXQP:
        pRcAttr->stMjpegFixQp.u32Qfactor = u32FixIQp;
        break;
    case VENC_RC_MODE_H264FIXQP:
        pRcAttr->stH264FixQp.u32IQp = u32FixIQp;
        pRcAttr->stH264FixQp.u32PQp = u32FixPQp;
        pRcAttr->stH264FixQp.u32BQp = u32FixBQp;
        break;
    case VENC_RC_MODE_H265FIXQP:
        pRcAttr->stH265FixQp.u32IQp = u32FixIQp;
        pRcAttr->stH265FixQp.u32PQp = u32FixPQp;
        pRcAttr->stH265FixQp.u32BQp = u32FixBQp;
        break;
    default:
        return RK_ERR_VENC_NOT_SUPPORT;
    }

    return RK_SUCCESS;
}

#ifdef RK3588

static RK_S32 rockchip_set_startTime(VENC_RC_ATTR_S *pRcAttr, RK_U32 u32StatTime)
{
    switch (pRcAttr->enRcMode)
    {
    case VENC_RC_MODE_MJPEGCBR:
        pRcAttr->stMjpegCbr.u32StatTime = u32StatTime;
        break;
    case VENC_RC_MODE_H264CBR:
        pRcAttr->stH264Cbr.u32StatTime = u32StatTime;
        break;
    case VENC_RC_MODE_H265CBR:
        pRcAttr->stH265Cbr.u32StatTime = u32StatTime;
        break;
    case VENC_RC_MODE_MJPEGVBR:
        pRcAttr->stMjpegVbr.u32StatTime = u32StatTime;
        break;
    case VENC_RC_MODE_H264VBR:
        pRcAttr->stH264Vbr.u32StatTime = u32StatTime;
        break;
    case VENC_RC_MODE_H265VBR:
        pRcAttr->stH265Vbr.u32StatTime = u32StatTime;
        break;
    case VENC_RC_MODE_H264AVBR:
        pRcAttr->stH264Avbr.u32StatTime = u32StatTime;
        break;
    case VENC_RC_MODE_H265AVBR:
        pRcAttr->stH265Avbr.u32StatTime = u32StatTime;
        break;
    default:
        return RK_ERR_VENC_NOT_SUPPORT;
    }

    return RK_SUCCESS;
}
#else
static RK_S32 rockchip_set_startTime(VENC_RC_ATTR_S *pRcAttr, RK_U32 u32StatTime)
{
    return 0;
}

#endif

static struct rockchip_venc_priv *rockchip_venc_get_priv(struct ht_venc *pvenc, HT_S32 chn)
{
    struct rockchip_venc *plt_venc = container_of(pvenc, struct rockchip_venc, m_venc);

    if (chn >= VENC_MAX_CHN_NUM)
        return NULL;

    return &plt_venc->priv[chn];
}

#if 0
static RK_S32 rockchip_venc_pool_create(struct rockchip_venc_priv *priv)
{
    PIC_BUF_ATTR_S stPicBufAttr;
    MB_PIC_CAL_S stMbPicCalResult;
    MB_POOL_CONFIG_S stMbPoolCfg;
    RK_S32 s32Ret = -1;

    memset(&stPicBufAttr, 0, sizeof(PIC_BUF_ATTR_S));
    memset(&stMbPicCalResult, 0, sizeof(MB_PIC_CAL_S));

    stPicBufAttr.u32Width = priv->stAttr.stVencAttr.u32PicWidth;
    stPicBufAttr.u32Height = priv->stAttr.stVencAttr.u32PicHeight;
    stPicBufAttr.enPixelFormat = priv->stAttr.stVencAttr.enPixelFormat;
    stPicBufAttr.enCompMode = priv->enCompMode;

    s32Ret = RK_MPI_CAL_COMM_GetPicBufferSize(&stPicBufAttr, &stMbPicCalResult);
    if (s32Ret != RK_SUCCESS)
    {
        printf("get picture buffer size failed. err 0x%x", s32Ret);
        return RK_FAILURE;
    }

    priv->u32PoolSize = stMbPicCalResult.u32MBSize;
    if (priv->u32PoolSize > 8192 * 8192 * 4)
    {
        printf("too large picture size: %d", priv->u32PoolSize);
        return RK_FAILURE;
    }

    memset(&stMbPoolCfg, 0, sizeof(MB_POOL_CONFIG_S));

    stMbPoolCfg.u64MBSize = priv->u32PoolSize;
    stMbPoolCfg.u32MBCnt = 10;
    stMbPoolCfg.enAllocType = MB_ALLOC_TYPE_DMA;
    stMbPoolCfg.bPreAlloc = RK_TRUE;

    priv->vencPoolInput = RK_MPI_MB_CreatePool(&stMbPoolCfg);
    if (priv->vencPoolInput == MB_INVALID_POOLID)
    {
        printf("create vencPoolInput failed!");
        return RK_FAILURE;
    }

    return RK_SUCCESS;
}
#endif

RK_S32 rockchip_venc_init(struct ht_venc *pvenc, RK_U32 chn, RK_U32 u32SrcWidth, RK_U32 u32SrcHeight, HT_CODEC_ID codec)
{
    struct rockchip_venc_priv *priv = NULL;
    //    VENC_CHN_ATTR_S stAttr;
    VENC_RECV_PIC_PARAM_S stRecvParam;
    //	VENC_CHN_PARAM_S stParam;
    //    VENC_PARAM_MOD_S stModParam;
    RK_S32 s32Ret = -1;

    priv = rockchip_venc_get_priv(pvenc, chn);

    if (!priv)
        return -1;

    priv->enCompMode = COMPRESS_MODE_NONE;
    priv->chn = chn;
    priv->pool_enabled = RK_FALSE;

//	PIC_BUF_ATTR_S	 stPicBufAttr;
//	MB_PIC_CAL_S     stMbPicCalResult;
//	0 1 2 3 4 5
//	6 7 8 9 10 11
//	stPicBufAttr.u32Width	   = u32SrcWidth;
//	stPicBufAttr.u32Height	   = u32SrcHeight;
//	stPicBufAttr.enCompMode    = COMPRESS_MODE_NONE;
//	stPicBufAttr.enPixelFormat = RK_FMT_YUV420SP;

//	s32Ret = RK_MPI_CAL_VGS_GetPicBufferSize(&stPicBufAttr, &stMbPicCalResult);

    memset(&priv->stAttr, 0, sizeof(VENC_CHN_ATTR_S));

#if 1
    priv->stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    priv->stAttr.stRcAttr.stH264Cbr.u32Gop = 30;

    //	//	10240kbps
    priv->stAttr.stRcAttr.stH264Cbr.u32BitRate = 4096;

    //	//	10240kbps
    rockchip_set_bitrate(&priv->stAttr.stRcAttr, 4096, 0, 0);
    rockchip_set_fixqp(&priv->stAttr.stRcAttr, 0, 2, 0);
    rockchip_set_startTime(&priv->stAttr.stRcAttr, 3);

//	s32Ret = RK_MPI_VENC_SetChnAttr(chn, &stAttr);
//	if (s32Ret)
//		return RK_FAILURE;
#endif

    //	stAttr.stGopAttr.enGopMode = VENC_GOPMODE_NORMALP;
    priv->stAttr.stVencAttr.enType = rockchip_venc_codec(codec);
    priv->stAttr.stVencAttr.u32Profile = H264E_PROFILE_HIGH;
    priv->stAttr.stVencAttr.enPixelFormat = RK_FMT_YUV420SP;
    priv->stAttr.stVencAttr.u32PicWidth = u32SrcWidth;
    priv->stAttr.stVencAttr.u32PicHeight = u32SrcHeight;
    priv->stAttr.stVencAttr.u32VirWidth = u32SrcWidth;
    priv->stAttr.stVencAttr.u32VirHeight = u32SrcHeight;
    priv->stAttr.stVencAttr.u32StreamBufCnt = 5;
    priv->stAttr.stVencAttr.u32BufSize = u32SrcWidth * u32SrcHeight * 3 / 2;
    //	stAttr.stVencAttr.u32BufSize		= stMbPicCalResult.u32MBSize;
    //	stAttr.stVencAttr.u32Depth = 1;

    s32Ret = RK_MPI_VENC_CreateChn(chn, &priv->stAttr);
    if (s32Ret)
        return RK_FAILURE;

    //	VENC_RC_PARAM_S venc_rc_param;
    //	RK_MPI_VENC_GetRcParam(chn, &venc_rc_param);
    //	venc_rc_param.stParamH264.u32MinQp = 15;
    //	RK_MPI_VENC_SetRcParam(chn, &venc_rc_param);
    //
    //	VENC_SLICE_SPLIT_S stSliceSplit;
    //	RK_MPI_VENC_GetSliceSplit(chn, &stSliceSplit);
    //	stSliceSplit.bSplitEnable = 1;
    //	stSliceSplit.u32SplitMode = 2;
    //	stSliceSplit.u32SplitSize = 1;
    //	RK_MPI_VENC_SetSliceSplit(chn, &stSliceSplit);

    //	memset(&stModParam, 0, sizeof(VENC_PARAM_MOD_S));
    //
    //	stModParam.enVencModType = MODTYPE_H264E;
    //	stModParam.stH264eModParam.u32OneStreamBuffer = 1;
    //
    //	s32Ret = RK_MPI_VENC_SetModParam(chn, &stModParam);
    //	if (s32Ret)
    //		return RK_FAILURE;

    memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S));
    stRecvParam.s32RecvPicNum = -1;

    return (RK_MPI_VENC_StartRecvFrame(chn, &stRecvParam));
}

static RK_S32 rockchip_venc_exit(struct ht_venc *pvenc, HT_U32 chn)
{
    RK_S32 s32Ret = -1;

    s32Ret = RK_MPI_VENC_StopRecvFrame(chn);

    if (s32Ret)
        return RK_FAILURE;

    s32Ret = RK_MPI_VENC_DestroyChn(chn);

    return s32Ret;
}

static HT_S32 rockchip_venc_get_frame_pthread(struct pthread_work *pwork, HT_VOID *user)
{
	RK_S32 s32Ret = RK_SUCCESS;
	VENC_STREAM_S stVencStream;
	void *pData = RK_NULL;
	struct rockchip_venc_priv *priv = (struct rockchip_venc_priv *)user;
	
	stVencStream.pstPack = (VENC_PACK_S *)calloc(1, sizeof(VENC_PACK_S));
	
	while (RK_TRUE)
	{
		stVencStream.u32PackCount = 1;

		s32Ret = RK_MPI_VENC_GetStream(priv->chn, &stVencStream, -1);

		if (s32Ret >= 0)
		{
			pData = RK_MPI_MB_Handle2VirAddr(stVencStream.pstPack->pMbBlk);
			RK_MPI_SYS_MmzFlushCache(stVencStream.pstPack->pMbBlk, RK_TRUE);

			priv->user_cb(priv->user, pData, stVencStream.pstPack->u32Len, stVencStream.pstPack->u64PTS);

			if (stVencStream.pstPack->bStreamEnd == RK_TRUE)
			{
				RK_MPI_VENC_ReleaseStream(priv->chn, &stVencStream);
				break;
			}

			RK_MPI_VENC_ReleaseStream(priv->chn, &stVencStream);
		}
//		else
//		{
//			printf("venc get frame timeout!!!\n");
//			assert(0);
//		}
	}

	if (stVencStream.pstPack)
		free(stVencStream.pstPack);

	return 0;
}

/*
**
**	若当前VENC通道还绑定后级时
**	当前vhn已无法getframe，需要新建一个venc并和前级绑定才能获取帧
**
*/
static RK_S32 rockchip_venc_get_frame(struct ht_venc *pvenc, HT_U32 chn, cb_venc_get_frame cb_user_get_frame, void *user)
{
    RK_S32 s32Ret = RK_SUCCESS;
	struct rockchip_venc *plt_venc = container_of(pvenc, struct rockchip_venc, m_venc);
	struct rockchip_venc_priv *priv = NULL;

	//	TODO check chn availd ...

	//	TODO check pthread status ...
	
	priv = (struct rockchip_venc_priv *)calloc(1, sizeof(struct rockchip_venc_priv));
	if (!priv)
		return -2;

	
	snprintf(priv->stPthreadName, sizeof(priv->stPthreadName), "rk_venc_%d", chn);
	
	printf("rockchip_venc_get_frame ... %s\n", priv->stPthreadName);

	priv->chn 		= chn;
	priv->user_cb 	= cb_user_get_frame;
	priv->user 		= user;
	
	s32Ret = ht_pthread_request_work_always(&plt_venc->pthread, priv->stPthreadName, 
										rockchip_venc_get_frame_pthread, (HT_VOID *)priv);
    
	return s32Ret;
}

#if 0
static RK_S32 rockchip_venc_create_frame(struct rockchip_venc_priv *priv)
{
	RK_S32 s32Ret = -1;
	MB_POOL mbPool = MB_INVALID_POOLID;
	
	MB_BLK blk = RK_NULL;

	memset(&pinfo, 0, sizeof(struct rockchip_venc_pool));
	
	s32Ret = rockchip_venc_pool_create(priv, &pinfo);
	if (s32Ret)
		return RK_FAILURE;
	
	blk = RK_MPI_MB_GetMB(pinfo.vencPoolInput, pinfo.u32PoolSize, RK_TRUE);

	if (RK_NULL == blk)
	{
		printf("RK_MPI_MB_GetMB failed !\n");
	}

	s32Ret = RK_MPI_SYS_MmzFlushCache(blk, RK_FALSE);
	if (s32Ret)
		return RK_FAILURE;

	priv->pframe = (VIDEO_FRAME_INFO_S *)calloc(1, sizeof(VIDEO_FRAME_INFO_S));

	if (!priv->pframe)
		return RK_FAILURE;
	
	priv->pframe->stVFrame.pMbBlk 			= blk;
	priv->pframe->stVFrame.u32Width 		= priv->stAttr.stVencAttr.u32PicWidth;
	priv->pframe->stVFrame.u32Height 		= priv->stAttr.stVencAttr.u32PicHeight;
	priv->pframe->stVFrame.u32VirWidth 		= priv->stAttr.stVencAttr.u32VirWidth;
	priv->pframe->stVFrame.u32VirHeight 	= priv->stAttr.stVencAttr.u32VirHeight;
	priv->pframe->stVFrame.enPixelFormat 	= priv->stAttr.stVencAttr.enPixelFormat;
//	priv->pframe->stVFrame.u32FrameFlag 	|= s32ReachEOS ? FRAME_FLAG_SNAP_END : 0;
	priv->pframe->stVFrame.enCompressMode 	= priv->enCompMode;

	return RK_SUCCESS;
}
#endif

#if 0
static RK_S32 rockchip_venc_send_frame(struct ht_venc *pvenc, HT_U32 chn, void *pframe, HT_S32 s32MilliSec)
{
    VIDEO_FRAME_INFO_S stFrame;
    RK_S32 s32Ret = -1;
    struct rockchip_venc_priv *priv = rockchip_venc_get_priv(pvenc, chn);
    MB_BLK blk = RK_NULL;

    if (!priv)
        return RK_FAILURE;

    if (priv->pool_enabled == RK_FALSE)
    {
        s32Ret = rockchip_venc_pool_create(priv);
        if (s32Ret != RK_SUCCESS)
            return RK_FAILURE;

        priv->pool_enabled = RK_TRUE;
    }

    blk = RK_MPI_MB_GetMB(priv->vencPoolInput, priv->u32PoolSize, RK_TRUE);
    if (RK_NULL == blk)
    {
        printf("RK_MPI_MB_GetMB failed !\n");
        return RK_FAILURE;
    }

    s32Ret = RK_MPI_SYS_MmzFlushCache(blk, RK_FALSE);
    if (s32Ret)
    {
        RK_MPI_MB_ReleaseMB(blk);
        return RK_FAILURE;
    }

    memset(&stFrame, 0, sizeof(VIDEO_FRAME_INFO_S));
    stFrame.stVFrame.pMbBlk = blk;
    stFrame.stVFrame.u32Width = priv->stAttr.stVencAttr.u32PicWidth;
    stFrame.stVFrame.u32Height = priv->stAttr.stVencAttr.u32PicHeight;
    stFrame.stVFrame.u32VirWidth = priv->stAttr.stVencAttr.u32VirWidth;
    stFrame.stVFrame.u32VirHeight = priv->stAttr.stVencAttr.u32VirHeight;
    stFrame.stVFrame.enPixelFormat = priv->stAttr.stVencAttr.enPixelFormat;
    //	stFrame.stVFrame.u32FrameFlag 		|= s32ReachEOS ? FRAME_FLAG_SNAP_END : 0;
    stFrame.stVFrame.enCompressMode = priv->enCompMode;

    printf("\033[0m\033[1;31m---------\033[0m\n");

    s32Ret = RK_MPI_VENC_SendFrame(chn, &stFrame, -1);
    if (s32Ret)
        printf("RK_MPI_VENC_SendFrame error %08x\n", s32Ret);

    s32Ret = RK_MPI_MB_ReleaseMB(blk);
    if (s32Ret)
        printf("RK_MPI_MB_ReleaseMB error %08x\n", s32Ret);

    return s32Ret;
}
#endif

static RK_S32 rockchip_stop_recv_frame(struct ht_venc *pvenc, HT_U32 chn)
{
    struct rockchip_venc_priv *priv = rockchip_venc_get_priv(pvenc, chn);
    RK_S32 s32Ret = -1;

//    if (!priv)
//        return RK_FAILURE;
	printf("rockchip_stop_recv_frame ...\n");

    s32Ret = RK_MPI_VENC_StopRecvFrame(chn);
    if (s32Ret)
        printf("RK_MPI_VENC_StopRecvFrame error (%08x)\n", s32Ret);

    s32Ret |= RK_MPI_VENC_DestroyChn(chn);
    if (s32Ret)
        printf("RK_MPI_VENC_DestroyChn error (%08x)\n", s32Ret);


	printf("rockchip_stop_recv_frame ... done\n");
    return s32Ret;
}


static RK_S32 rockchip_venc_send_frame1(struct ht_venc *pvenc, HT_U32 chn, void *pframe, HT_S32 s32MilliSec)
{
    RK_S32 s32Ret = -1;
    // VIDEO_FRAME_INFO_S *stFrame = (VIDEO_FRAME_INFO_S *)pframe;
    //	VIDEO_FRAME_INFO_S test;

    if (!pframe)
        return RK_FAILURE;

    //	printf("blk = %d\n", stFrame->stVFrame.pMbBlk);
    //	printf("width = %d\n", stFrame->stVFrame.u32Width);
    //	printf("heigth = %d\n", stFrame->stVFrame.u32Height);
    //	printf("vwidth = %d\n", stFrame->stVFrame.u32VirWidth);
    //	printf("vheigth = %d\n", stFrame->stVFrame.u32VirHeight);

    s32Ret = RK_MPI_VENC_SendFrame(chn, pframe, s32MilliSec);
    if (s32Ret)
        printf("RK_MPI_VENC_SendFrame error %08x\n", s32Ret);

//    printf("venc send .... %d\n", s32Ret);
    return s32Ret;
}

static struct ht_venc_ops g_venc_ops = {
    .venc_init = rockchip_venc_init,
    .venc_exit = rockchip_venc_exit,
    .venc_get_frame = rockchip_venc_get_frame,
    .venc_stop_recv_frame = rockchip_stop_recv_frame,
    .venc_send_frame = rockchip_venc_send_frame1,
};

static HT_S32 rockchip_venc_default_config(struct rockchip_venc *plt_venc)
{
	HT_S32 ret = -1;
	
	ret = ht_pthread_init(&plt_venc->pthread, "rockchip_venc");
	if (ret)
	{
		printf("pthread init faild %d\n", ret);
		return -2;
	}
	
	return 0;
}

__init static RK_S32 rockchip_venc_register(void)
{
    RK_S32 ret = -1;
    struct rockchip_venc *plt_venc = (struct rockchip_venc *)calloc(1, sizeof(struct rockchip_venc));
    struct ht_venc *pvenc = NULL;

    if (!plt_venc)
        return -1;

	ret = rockchip_venc_default_config(plt_venc);
	if (ret)
		return ret;
	
    pvenc = &plt_venc->m_venc;

    pvenc->ops = &g_venc_ops;

    ret = ht_venc_module_register(pvenc);

    return ret;
}
